package com.zxy.ziems.server.file.service;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zxy.btp.common.exception.ConditionException;
import com.zxy.ziems.server.file.configure.FileProperties;
import com.zxy.ziems.server.file.constant.FileStatusConst;
import com.zxy.ziems.server.file.dto.FileDto;
import com.zxy.ziems.server.file.entity.FileEntity;
import com.zxy.ziems.server.file.enums.FileTypeEnum;
import com.zxy.ziems.server.file.mapper.FileMapper;
import com.zxy.ziems.server.file.util.DateUtil;
import com.zxy.ziems.server.file.util.FileSupport;
import com.zxy.ziems.server.file.util.FileUtil;
import com.zxy.ziems.server.file.vo.FileVO;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.Objects;

/**
 * @author chdzq
 * @create 2023/3/21
 */
@Service
@Slf4j
public class FileService extends ServiceImpl<FileMapper, FileEntity> {

    @Autowired
    private FileProperties config;

    public FileVO add(FileDto dto) throws Exception {
        String parentId = dto.getParentId() == null ? "0" : dto.getParentId();
        String fileName = dto.getFileName();
        Long fileSize = dto.getFileSize();
        String name = FileSupport.generateRandomFileName.get();
        FileEntity fileEntity = new FileEntity();
        fileEntity.setParentId(parentId);
        fileEntity.setFileName(fileName);
        fileEntity.setFilePath(this.getFilePath(name, FileUtil.getSuffixByPath.apply(fileName)));
        fileEntity.setFileSize(fileSize);
        fileEntity.setStatus(FileStatusConst.FILE_STATUS_ING);
        this.save(fileEntity);
        return FileVO.builder()
                .id(fileEntity.getId())
                .name(fileName)
                .size(fileSize)
                .build();
    }

    public void downloadById(String id, Boolean isOnline, HttpServletResponse response) throws UnsupportedEncodingException {
        FileEntity entity = getById(id);
        if (entity != null && Objects.equals(FileStatusConst.FILE_STATUS_FINISH, entity.getStatus())) {
            if (isOnline) {
                if (Objects.equals(entity.getType(), FileTypeEnum.DIR.getValue()) || Objects.equals(entity.getType(), FileTypeEnum.DOC.getValue()) || Objects.equals(entity.getType(), FileTypeEnum.OTHER.getValue())) {
                    throw new ConditionException("暂不支持此格式预览");
                }

                response.setContentType(entity.getType() + File.separator + (String) FileUtil.getSuffixByPath.apply(entity.getFilePath()));
                response.addHeader("Content-Disposition", "inline;fileName=" + URLEncoder.encode(entity.getFileName(), "utf-8"));
            } else {
                response.setContentType("multipart/form-data");
                response.addHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(entity.getFileName(), "utf-8"));
            }

            response.addHeader("Content-Length", String.valueOf(entity.getFileSize()));
            FileSupport.download.accept(entity.getFilePath(), response);
        } else {
            throw new ConditionException("文件不存在");
        }
    }

    public BigDecimal processById(String id) throws Exception {
        log.info("查询文件上传成功,文件id -> {},timestamp ->{}", id, LocalDateTime.now());
        FileEntity entity = this.getById(id);
        if (entity == null) {
            throw new ConditionException("文件不存在");
        } else {
            return FileSupport.process(entity.getFilePath());
        }
    }

    public FileVO viewById(String id) {
        if (StrUtil.isBlank(id)) {
            return null;
        }
        FileEntity entity = getById(id);
        return FileVO.makeBy(entity);
    }

    private String getFilePath(String name, String suffix) {
        StringBuilder builder = new StringBuilder(this.config.getBaseUrl());
        builder.append((String) DateUtil.todayStr.apply("yyyyMMdd") + File.separator);
        builder.append(name.concat(File.separator));
        builder.append(name.concat(".").concat(suffix));

        return builder.toString();
    }

    private FileEntity checkFile(String id) throws Exception {

        FileEntity fileEntity = getById(id);
        if (fileEntity == null) {
            throw new ConditionException("文件不存在");
        } else if (Objects.equals(FileStatusConst.FILE_STATUS_FINISH, fileEntity.getStatus())) {
            throw new ConditionException("文件已经上传");
        } else {
            return fileEntity;
        }
    }

    public FileVO upload(String id, MultipartFile file, HttpServletRequest request) throws Exception {

        FileEntity fileEntity = this.checkFile(id);

        Assert.isTrue(file.getSize() == fileEntity.getFileSize(), "上传的文件大小不一致");
        Assert.isTrue(fileEntity.getFileName().equals(file.getOriginalFilename()), "上传的文件名称不一致");

        String path = fileEntity.getFilePath();
        File toFile = new File(path);

        if (!toFile.getParentFile().exists()) {
            toFile.getParentFile().mkdirs();
        }
        InputStream fileStream = file.getInputStream();

        FileOutputStream fos = new FileOutputStream(toFile);
        int i = 0;
        byte[] buffer = new byte[1024];
        while ((i = fileStream.read(buffer)) > 0) {
            fos.write(buffer, 0, i);
        }
        fos.flush();
        fos.close();

        fileEntity.setMd5(FileUtil.md5(file));
        fileEntity.setType(FileUtil.getMineType.apply(fileEntity.getFilePath()));
        fileEntity.setStatus(FileStatusConst.FILE_STATUS_FINISH);
        this.updateById(fileEntity);

        return FileVO.makeBy(fileEntity);
    }
}
